import logging
import networkx as nx
from typing import Dict, List, Any, Optional
from app.services.dhgam.dhged_service import DynamicHeterogeneousGraphEventDetection
from app.schemas.facenet_base_schema import TaskStatus
from app.schemas.dhgam.dhged_schema import Graph, DetectedEvent, EventExplanation

logger = logging.getLogger(__name__)

class DHGEDApiService:
    """动态异构图异常事件检测服务API"""
    
    def __init__(self):
        self.service_instances = {}  # 存储各任务的服务实例
    
    def _convert_to_networkx_graph(self, graph_data: Graph) -> nx.Graph:
        """将Schema格式的图转换为NetworkX图对象"""
        G = nx.Graph()
        
        # 添加节点
        for node in graph_data.nodes:
            node_attrs = {"type": node.type}
            if node.properties:
                node_attrs.update(node.properties)
            G.add_node(node.id, **node_attrs)
        
        # 添加边
        for edge in graph_data.edges:
            edge_attrs = {"type": edge.type}
            if edge.properties:
                edge_attrs.update(edge.properties)
            G.add_edge(edge.source, edge.target, **edge_attrs)
        
        return G
    
    def _convert_to_schema_event(self, event: Dict[str, Any]) -> DetectedEvent:
        """将服务输出的事件转换为Schema格式"""
        return DetectedEvent(
            time_idx=event["time_idx"],
            pattern=event["pattern"],
            affected_nodes=event["affected_nodes"],
            affected_edges=event["affected_edges"],
            score=event["score"],
            models_score=event.get("models_score"),
            combined_score=event.get("combined_score"),
            is_anomaly=event.get("is_anomaly"),
            total_changes=event.get("total_changes")
        )
    
    async def fit_model(self, input_params: Dict[str, Any], task_id: str) -> Dict[str, Any]:
        """训练模型并检测事件
        
        Args:
            input_params: 包含图序列和模型参数的输入
            task_id: 任务ID
            
        Returns:
            Dict: 包含任务状态和检测到的事件的响应
        """
        try:
            # 获取输入参数
            graph_sequence_data = input_params.get("graph_sequence", [])
            model_params = input_params.get("model_params", {})
            
            # 转换为NetworkX图对象
            graph_sequence = [
                self._convert_to_networkx_graph(graph) 
                for graph in graph_sequence_data
            ]
            
            # 创建服务实例
            service = DynamicHeterogeneousGraphEventDetection(
                embedding_dim=model_params.get("embedding_dim", 64),
                hidden_dim=model_params.get("hidden_dim", 32),
                window_size=model_params.get("window_size", 5),
                anomaly_threshold=model_params.get("anomaly_threshold", 0.9)
            )
            
            # 存储服务实例
            self.service_instances[task_id] = service
            
            # 训练模型并检测事件
            events = service.fit(graph_sequence)
            
            # 转换事件格式
            schema_events = [self._convert_to_schema_event(event) for event in events]
            
            # 返回响应
            return {
                "task_id": task_id,
                "task_status": TaskStatus.COMPLETED,
                "task_progress": 100,
                "output_params": {
                    "detected_events": [event.dict() for event in schema_events],
                    "total_events": len(schema_events)
                }
            }
            
        except Exception as e:
            logger.error(f"DHGED模型训练失败: {str(e)}", exc_info=True)
            return {
                "task_id": task_id,
                "task_status": TaskStatus.FAILED,
                "task_progress": 0,
                "error_message": f"模型训练失败: {str(e)}"
            }
    
    async def detect_events(self, input_params: Dict[str, Any], task_id: str) -> Dict[str, Any]:
        """检测新图中的事件
        
        Args:
            input_params: 包含新图和可选的历史图的输入
            task_id: 任务ID
            
        Returns:
            Dict: 包含任务状态和检测到的事件的响应
        """
        try:
            # 获取服务实例
            service = self.service_instances.get(task_id)
            if not service:
                return {
                    "task_id": task_id,
                    "task_status": TaskStatus.FAILED,
                    "error_message": "请先训练模型"
                }
            
            # 获取输入参数
            new_graph_data = input_params.get("new_graph")
            previous_graphs_data = input_params.get("previous_graphs")
            
            # 转换为NetworkX图对象
            new_graph = self._convert_to_networkx_graph(new_graph_data)
            
            previous_graphs = None
            if previous_graphs_data:
                previous_graphs = [
                    self._convert_to_networkx_graph(graph) 
                    for graph in previous_graphs_data
                ]
            
            # 检测事件
            events = service.detect_events(new_graph, previous_graphs)
            
            # 转换事件格式
            schema_events = [self._convert_to_schema_event(event) for event in events]
            
            # 返回响应
            return {
                "task_id": task_id,
                "task_status": TaskStatus.COMPLETED,
                "task_progress": 100,
                "output_params": {
                    "detected_events": [event.dict() for event in schema_events],
                    "total_events": len(schema_events)
                }
            }
            
        except Exception as e:
            logger.error(f"DHGED事件检测失败: {str(e)}", exc_info=True)
            return {
                "task_id": task_id,
                "task_status": TaskStatus.FAILED,
                "task_progress": 0,
                "error_message": f"事件检测失败: {str(e)}"
            }
    
    async def explain_event(self, input_params: Dict[str, Any], task_id: str) -> Dict[str, Any]:
        """解释检测到的事件
        
        Args:
            input_params: 包含事件的输入
            task_id: 任务ID
            
        Returns:
            Dict: 包含任务状态和事件解释的响应
        """
        try:
            # 获取服务实例
            service = self.service_instances.get(task_id)
            if not service:
                return {
                    "task_id": task_id,
                    "task_status": TaskStatus.FAILED,
                    "error_message": "请先训练模型"
                }
            
            # 获取输入参数
            event_data = input_params.get("event")
            
            # 解释事件
            explanation = service.explain_event(event_data)
            
            # 返回响应
            return {
                "task_id": task_id,
                "task_status": TaskStatus.COMPLETED,
                "task_progress": 100,
                "output_params": {
                    "explanation": explanation
                }
            }
            
        except Exception as e:
            logger.error(f"DHGED事件解释失败: {str(e)}", exc_info=True)
            return {
                "task_id": task_id,
                "task_status": TaskStatus.FAILED,
                "task_progress": 0,
                "error_message": f"事件解释失败: {str(e)}"
            } 